a tool for shared writing and social publishing
at update/thread-viewer 82 lines 2.5 kB view raw
1import { z } from "zod"; 2import { makeRoute } from "../lib"; 3import type { Env } from "./route"; 4import { idResolver } from "app/(home-pages)/reader/idResolver"; 5import { supabaseServerClient } from "supabase/serverClient"; 6import { Agent } from "@atproto/api"; 7import { getIdentityData } from "actions/getIdentityData"; 8import { createOauthClient } from "src/atproto-oauth"; 9import { 10 normalizePublicationRow, 11 hasValidPublication, 12} from "src/utils/normalizeRecords"; 13import { deduplicateByUri } from "src/utils/deduplicateRecords"; 14 15export type GetProfileDataReturnType = Awaited< 16 ReturnType<(typeof get_profile_data)["handler"]> 17>; 18 19export const get_profile_data = makeRoute({ 20 route: "get_profile_data", 21 input: z.object({ 22 didOrHandle: z.string(), 23 }), 24 handler: async ({ didOrHandle }, { supabase }: Pick<Env, "supabase">) => { 25 // Resolve handle to DID if necessary 26 let did = didOrHandle; 27 28 if (!didOrHandle.startsWith("did:")) { 29 const resolved = await idResolver.handle.resolve(didOrHandle); 30 if (!resolved) { 31 throw new Error("Could not resolve handle to DID"); 32 } 33 did = resolved; 34 } 35 let agent; 36 let authed_identity = await getIdentityData(); 37 if (authed_identity?.atp_did) { 38 try { 39 const oauthClient = await createOauthClient(); 40 let credentialSession = await oauthClient.restore( 41 authed_identity.atp_did, 42 ); 43 agent = new Agent(credentialSession); 44 } catch (e) { 45 agent = new Agent({ 46 service: "https://public.api.bsky.app", 47 }); 48 } 49 } else { 50 agent = new Agent({ 51 service: "https://public.api.bsky.app", 52 }); 53 } 54 55 let profileReq = agent.app.bsky.actor.getProfile({ actor: did }); 56 57 let publicationsReq = supabase 58 .from("publications") 59 .select("*") 60 .eq("identity_did", did); 61 62 let [{ data: profile }, { data: rawPublications }] = await Promise.all([ 63 profileReq, 64 publicationsReq, 65 ]); 66 67 // Deduplicate records that may exist under both pub.leaflet and site.standard namespaces 68 const publications = deduplicateByUri(rawPublications || []); 69 70 // Normalize publication records before returning 71 const normalizedPublications = publications 72 .map(normalizePublicationRow) 73 .filter(hasValidPublication); 74 75 return { 76 result: { 77 profile, 78 publications: normalizedPublications, 79 }, 80 }; 81 }, 82});